package com.net.xpay.openapi.protocol;


import com.google.common.base.Strings;
import com.net.common.exception.BusinessException;
import com.net.common.util.NetUtil;
import com.net.common.util.SerializationUtil;
import com.net.xpay.common.domain.User;
import com.net.xpay.common.domain.openapi.OpenApp;
import com.net.xpay.common.enums.openapi.OpenAppStatus;
import com.net.xpay.common.enums.user.SecurityStatus;
import com.net.xpay.common.manager.UserManager;
import com.net.xpay.common.manager.openapi.OpenAppManager;
import com.net.xpay.core.constant.PoseidonErrorCode;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

/**
 * 提供基础能力
 * 验证签名
 * 生成签名
 * 验证服务器白名单
 */
@Slf4j
@Component
public class OpenApiBase {

    @Autowired
    private OpenAppManager openAppManager;

    @Autowired
    private UserManager userManager;

    /**
     * 验证签名 服务器白名单
     */
    public OpenApp checkProtocol(HttpServletRequest request, OpenApiProtocol openApiProtocol) {
        String ip = NetUtil.getRequestRealIp(request);
        log.info("checkProtocol ip={}|uri={}|params={}", ip, request.getRequestURI(), SerializationUtil.obj2String(openApiProtocol));
        if (openApiProtocol == null) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "请求体不能为空");
        }
        if (Strings.isNullOrEmpty(openApiProtocol.getAppId())) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "应用id不能为空");
        }
        if (Strings.isNullOrEmpty(openApiProtocol.getTimestamp())) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "时间戳不能为空");
        }
        if (openApiProtocol.getTimestamp().length() < 13) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "请使用毫秒级时间戳");
        }
        long timestamp;
        try {
            timestamp = Long.parseLong(openApiProtocol.getTimestamp());
        } catch (Exception e) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "非法的时间戳参数");
        }

        if (timestamp + 1000 * 60 * 60L < System.currentTimeMillis()) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "时间戳已过期，有效期为1小时");
        }

        if (Strings.isNullOrEmpty(openApiProtocol.getSign())) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "签名不能为空");
        }
        if (Strings.isNullOrEmpty(openApiProtocol.getBizContent())) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "bizContent不能为空");
        }
        OpenApp openApp = openAppManager.getById(Long.valueOf(openApiProtocol.getAppId()));
        if (openApp == null) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "应用不存在");
        }
        if (openApp.getStatus() != OpenAppStatus.OPEN) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "应用未上线");
        }
        User user = userManager.getById(openApp.getUserId());
        if (user.getSecurityStatus() != SecurityStatus.NORMAL) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "应用归属商户状态异常");
        }
        //验证签名
        checkSign(openApp.getAppPublicKey(), openApiProtocol);

        //验证ip白名单
        checkWhiteIp(openApp, ip);

        return openApp;
    }

    private void checkSign(String appPublicKey, OpenApiProtocol openApiProtocol) {
        if (Strings.isNullOrEmpty(appPublicKey)) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "应用公钥未配置");
        }
        Map<String, String> params = new HashMap<>();
        params.put("appId", openApiProtocol.getAppId());
        params.put("timestamp", openApiProtocol.getTimestamp());
        params.put("sign", openApiProtocol.getSign());
        params.put("bizContent", openApiProtocol.getBizContent());
        if (!OpenApiSignature.rsaCheck(params, appPublicKey, "UTF-8")){
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "签名错误");
        }
    }

    private void checkWhiteIp(OpenApp openApp, String ip) {
        if (!openApp.getCheckIp()) {
            log.info("checkWhiteIp ip no check|id={}|userId={}|ip={}", openApp.getId(), openApp.getUserId(), ip);
            return;
        }
        if (CollectionUtils.isEmpty(openApp.getWhiteIps())) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "ip白名单未配置");
        }

        boolean eq = false;
        for (String whiteIp : openApp.getWhiteIps()) {
            if (whiteIp.equals(ip)) {
                eq = true;
                break;
            }
        }
        if (!eq) {
            log.info("checkWhiteIp ip no pass|id={}|userId={}|ip={}", openApp.getId(), openApp.getUserId(), ip);
            throw new BusinessException(PoseidonErrorCode.INVALID_CLIENT_IP, "当前ip(" + ip + ")不在IP白名单中");
        }

    }


}
